{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 基于关联规则的智能推荐"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>0</th>\n",
       "      <th>1</th>\n",
       "      <th>2</th>\n",
       "      <th>3</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>a</td>\n",
       "      <td>c</td>\n",
       "      <td>e</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>b</td>\n",
       "      <td>d</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>b</td>\n",
       "      <td>c</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>a</td>\n",
       "      <td>b</td>\n",
       "      <td>c</td>\n",
       "      <td>d</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>a</td>\n",
       "      <td>b</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   0  1    2    3\n",
       "0  a  c    e  NaN\n",
       "1  b  d  NaN  NaN\n",
       "2  b  c  NaN  NaN\n",
       "3  a  b    c    d\n",
       "4  a  b  NaN  NaN"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "from apriori import *  # 导入自行编写的apriori函数\n",
    "# 读入数据\n",
    "data = pd.read_excel('../data/menu_orders.xls', header=None)\n",
    "data.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "转换原始数据至0-1矩阵...\n",
      "\n",
      "转换完毕\n"
     ]
    }
   ],
   "source": [
    "print('\\n转换原始数据至0-1矩阵...')\n",
    "ct = lambda x: pd.Series(1, index=x[pd.notnull(x)])  # 转换0-1矩阵的过渡函数\n",
    "b = map(ct, data.to_numpy())  # 用map方式执行\n",
    "data = pd.DataFrame(list(b)).fillna(0)  # 实现矩阵转换，空值用0填充\n",
    "print('\\n转换完毕')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>a</th>\n",
       "      <th>c</th>\n",
       "      <th>e</th>\n",
       "      <th>b</th>\n",
       "      <th>d</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>1.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>1.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "     a    c    e    b    d\n",
       "0  1.0  1.0  1.0  0.0  0.0\n",
       "1  0.0  0.0  0.0  1.0  1.0\n",
       "2  0.0  1.0  0.0  1.0  0.0\n",
       "3  1.0  1.0  0.0  1.0  1.0\n",
       "4  1.0  0.0  0.0  1.0  0.0"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "正在进行第1次搜索...\n",
      "数目：6...\n",
      "\n",
      "正在进行第2次搜索...\n",
      "数目：3...\n",
      "\n",
      "正在进行第3次搜索...\n",
      "数目：0...\n",
      "\n",
      "结果为：\n",
      "           support  confidence\n",
      "e---a          0.3    1.000000\n",
      "e---c          0.3    1.000000\n",
      "c---e---a      0.3    1.000000\n",
      "a---e---c      0.3    1.000000\n",
      "c---a          0.5    0.714286\n",
      "a---c          0.5    0.714286\n",
      "a---b          0.5    0.714286\n",
      "c---b          0.5    0.714286\n",
      "b---a          0.5    0.625000\n",
      "b---c          0.5    0.625000\n",
      "a---c---e      0.3    0.600000\n",
      "b---c---a      0.3    0.600000\n",
      "a---c---b      0.3    0.600000\n",
      "a---b---c      0.3    0.600000\n"
     ]
    }
   ],
   "source": [
    "support = 0.2  # 最小支持度\n",
    "confidence = 0.5  # 最小置信度\n",
    "# 连接符，默认'--'，用来区分不同元素，如A--B。需要保证原始表格中不含有该字符\n",
    "ms = '---'\n",
    "find_rule(data, support, confidence, ms).to_excel('../tmp/outputfile.xls', encoding='utf-8')  # 保存结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "finalFrequent Item:  {'1'}\n",
      "condPattBases : 1 {frozenset({'3'}): 12917, frozenset({'6', '11', '3'}): 34141, frozenset({'6'}): 16461, frozenset({'11', '6'}): 43366, frozenset({'6', '3'}): 13436, frozenset({'11'}): 1882, frozenset({'11', '3'}): 1565}\n",
      "head from conditional tree:  {'3': [62059, <fpGrowth.treeNode object at 0x000001E893FEA6C8>], '6': [107404, <fpGrowth.treeNode object at 0x000001E893FEA788>], '11': [80954, <fpGrowth.treeNode object at 0x000001E893FEA7C8>]}\n",
      "conditional tree for:  {'1'}\n",
      "  Null Set   1\n",
      "   3   12917\n",
      "   6   107404\n",
      "    11   77507\n",
      "     3   34141\n",
      "    3   13436\n",
      "   11   3447\n",
      "    3   1565\n",
      "finalFrequent Item:  {'1', '6'}\n",
      "condPattBases : 6 {}\n",
      "head from conditional tree:  None\n",
      "finalFrequent Item:  {'1', '3'}\n",
      "condPattBases : 3 {frozenset({'11', '6'}): 34141, frozenset({'6'}): 13436, frozenset({'11'}): 1565}\n",
      "head from conditional tree:  None\n",
      "finalFrequent Item:  {'11', '1'}\n",
      "condPattBases : 11 {frozenset({'6'}): 77507}\n",
      "head from conditional tree:  {'6': [77507, <fpGrowth.treeNode object at 0x000001E894143B48>]}\n",
      "conditional tree for:  {'11', '1'}\n",
      "  Null Set   1\n",
      "   6   77507\n",
      "finalFrequent Item:  {'11', '1', '6'}\n",
      "condPattBases : 6 {}\n",
      "head from conditional tree:  None\n",
      "finalFrequent Item:  {'3'}\n",
      "condPattBases : 3 {frozenset({'11', '6'}): 117401, frozenset({'6'}): 68888, frozenset({'11'}): 9718}\n",
      "head from conditional tree:  {'11': [127119, <fpGrowth.treeNode object at 0x000001E89414B7C8>], '6': [186289, <fpGrowth.treeNode object at 0x000001E89414B788>]}\n",
      "conditional tree for:  {'3'}\n",
      "  Null Set   1\n",
      "   6   186289\n",
      "    11   117401\n",
      "   11   9718\n",
      "finalFrequent Item:  {'11', '3'}\n",
      "condPattBases : 11 {frozenset({'6'}): 117401}\n",
      "head from conditional tree:  {'6': [117401, <fpGrowth.treeNode object at 0x000001E89414BB08>]}\n",
      "conditional tree for:  {'11', '3'}\n",
      "  Null Set   1\n",
      "   6   117401\n",
      "finalFrequent Item:  {'6', '11', '3'}\n",
      "condPattBases : 6 {}\n",
      "head from conditional tree:  None\n",
      "finalFrequent Item:  {'6', '3'}\n",
      "condPattBases : 6 {}\n",
      "head from conditional tree:  None\n",
      "finalFrequent Item:  {'11'}\n",
      "condPattBases : 11 {frozenset({'6'}): 261773}\n",
      "head from conditional tree:  {'6': [261773, <fpGrowth.treeNode object at 0x000001E89414BE48>]}\n",
      "conditional tree for:  {'11'}\n",
      "  Null Set   1\n",
      "   6   261773\n",
      "finalFrequent Item:  {'11', '6'}\n",
      "condPattBases : 6 {}\n",
      "head from conditional tree:  None\n",
      "finalFrequent Item:  {'6'}\n",
      "condPattBases : 6 {}\n",
      "head from conditional tree:  None\n",
      "finalFrequent Item:  {'4'}\n",
      "condPattBases : 4 {frozenset({'7', '6'}): 250, frozenset({'11', '1', '6'}): 1545, frozenset({'7', '11', '6', '3'}): 514, frozenset({'6', '1', '3'}): 876, frozenset({'6', '11', '1', '3'}): 1381, frozenset({'1'}): 1257, frozenset({'6'}): 4502, frozenset({'11', '6'}): 4814, frozenset({'218'}): 179, frozenset({'6', '3', '218', '148', '11'}): 720, frozenset({'6', '3'}): 4001, frozenset({'3'}): 5295, frozenset({'148', '6', '3'}): 49, frozenset({'6', '11', '3'}): 4459, frozenset({'6', '7', '1', '3'}): 51, frozenset({'218', '11', '6'}): 218, frozenset({'7', '1', '3'}): 41, frozenset({'7', '6', '3'}): 245, frozenset({'27', '1', '3'}): 24, frozenset({'3', '6', '7', '1', '27', '11'}): 221, frozenset({'11', '3'}): 657, frozenset({'148', '218', '11', '6'}): 793, frozenset({'6', '3', '7', '1', '11'}): 172, frozenset({'6', '7', '1', '218', '148', '11'}): 110, frozenset({'6', '7', '1', '27', '11'}): 228, frozenset({'6', '3', '7', '27', '11'}): 547, frozenset({'11', '7', '27', '6'}): 675, frozenset({'11', '6', '27', '3'}): 268, frozenset({'11', '27', '6'}): 321, frozenset({'218', '11', '1', '6'}): 82, frozenset({'1', '3'}): 1015, frozenset({'218', '1'}): 33, frozenset({'6', '11', '7', '218', '148', '27'}): 138, frozenset({'7', '11', '1', '6'}): 159, frozenset({'3', '6', '1', '218', '148', '11'}): 480, frozenset({'1', '6'}): 997, frozenset({'6', '7', '1', '148', '11'}): 7, frozenset({'27', '1', '6'}): 42, frozenset({'218', '6', '11', '3'}): 186, frozenset({'11', '1'}): 138, frozenset({'27', '6'}): 185, frozenset({'7', '11', '6'}): 521, frozenset({'148'}): 58, frozenset({'148', '218', '6'}): 134, frozenset({'218', '3'}): 156, frozenset({'218', '7', '6'}): 18, frozenset({'6', '11', '1', '218', '148', '27'}): 65, frozenset({'11'}): 757, frozenset({'6', '1', '218', '148', '11'}): 572, frozenset({'3', '6', '11', '7', '218', '148', '27'}): 104, frozenset({'6', '3', '7', '1', '27'}): 54, frozenset({'148', '11', '6'}): 110, frozenset({'11', '1', '3'}): 112, frozenset({'218', '6', '3'}): 203, frozenset({'7', '27'}): 72, frozenset({'7'}): 203, frozenset({'7', '27', '6', '3'}): 166, frozenset({'6', '27', '1', '3'}): 32, frozenset({'3', '6', '7', '1', '218', '148'}): 12, frozenset({'218', '11', '3'}): 23, frozenset({'6', '27', '3'}): 176, frozenset({'218', '6'}): 216, frozenset({'7', '3'}): 202, frozenset({'148', '218'}): 57, frozenset({'6', '3', '1', '218', '148'}): 58, frozenset({'6', '7', '1', '218', '148'}): 11, frozenset({'148', '11'}): 14, frozenset({'6', '3', '1', '148', '11'}): 40, frozenset({'6', '11', '7', '1', '218', '148', '27'}): 142, frozenset({'27'}): 182, frozenset({'148', '218', '7', '6'}): 14, frozenset({'148', '218', '6', '3'}): 127, frozenset({'3', '6', '11', '218', '148', '27'}): 55, frozenset({'6', '3', '1', '218', '11'}): 75, frozenset({'148', '218', '1', '6'}): 77, frozenset({'3', '6', '7', '1', '218', '148', '11'}): 77, frozenset({'148', '6', '11', '3'}): 88, frozenset({'11', '27', '1'}): 6, frozenset({'27', '3'}): 160, frozenset({'6', '7', '218', '148', '11'}): 100, frozenset({'7', '27', '6'}): 189, frozenset({'148', '1', '6'}): 14, frozenset({'27', '1'}): 35, frozenset({'3', '6', '7', '1', '148', '27'}): 1, frozenset({'7', '1', '6'}): 51, frozenset({'148', '3'}): 53, frozenset({'3', '6', '7', '218', '148', '11'}): 110, frozenset({'148', '7', '11', '1'}): 1, frozenset({'7', '11'}): 19, frozenset({'148', '6'}): 42, frozenset({'6', '1', '218', '148', '27'}): 5, frozenset({'6', '3', '1', '27', '11'}): 84, frozenset({'11', '27', '1', '6'}): 114, frozenset({'218', '6', '1', '3'}): 60, frozenset({'7', '1'}): 50, frozenset({'218', '7', '6', '3'}): 14, frozenset({'7', '27', '1', '6'}): 43, frozenset({'3', '6', '11', '7', '1', '218', '148', '27'}): 130, frozenset({'218', '7', '11', '6'}): 35, frozenset({'7', '27', '1', '3'}): 11, frozenset({'3', '6', '11', '7', '1', '218', '27'}): 12, frozenset({'148', '218', '7', '3'}): 2, frozenset({'218', '1', '6'}): 61, frozenset({'218', '11'}): 15, frozenset({'148', '218', '27', '6'}): 5, frozenset({'148', '7', '11', '6'}): 14, frozenset({'6', '7', '1', '218', '11'}): 17, frozenset({'11', '27'}): 22, frozenset({'7', '27', '3'}): 73, frozenset({'6', '7', '1', '218', '148', '27'}): 8, frozenset({'148', '7', '6'}): 3, frozenset({'3', '6', '11', '7', '148', '27'}): 22, frozenset({'148', '6', '1', '3'}): 13, frozenset({'148', '11', '1', '6'}): 52, frozenset({'218', '7'}): 11, frozenset({'148', '1', '3'}): 9, frozenset({'148', '218', '3'}): 34, frozenset({'3', '6', '7', '218', '27', '11'}): 35, frozenset({'6', '11', '7', '148', '27'}): 14, frozenset({'218', '1', '3'}): 34, frozenset({'148', '218', '1', '3'}): 17, frozenset({'6', '7', '1', '218', '27', '11'}): 17, frozenset({'11', '27', '3'}): 17, frozenset({'6', '11', '218', '148', '27'}): 49, frozenset({'3', '6', '7', '218', '148', '27'}): 8, frozenset({'7', '27', '1'}): 18, frozenset({'6', '3', '218', '27', '11'}): 15, frozenset({'148', '27', '11', '6'}): 9, frozenset({'218', '27', '3'}): 4, frozenset({'218', '7', '27', '6'}): 10, frozenset({'148', '6', '27', '3'}): 4, frozenset({'11', '27', '1', '3'}): 8, frozenset({'3', '6', '1', '218', '27', '11'}): 5, frozenset({'3', '6', '11', '1', '218', '148', '27'}): 37, frozenset({'148', '218', '7', '27'}): 2, frozenset({'218', '6', '27', '3'}): 3, frozenset({'148', '27'}): 3, frozenset({'6', '3', '7', '218', '11'}): 29, frozenset({'148', '218', '1'}): 19, frozenset({'6', '3', '7', '218', '27'}): 8, frozenset({'7', '11', '3'}): 22, frozenset({'6', '3', '11', '148', '27'}): 10, frozenset({'6', '7', '1', '148', '27', '11'}): 6, frozenset({'6', '7', '218', '148', '27'}): 16, frozenset({'6', '1', '218', '27', '11'}): 4, frozenset({'6', '3', '7', '218', '148'}): 11, frozenset({'6', '3', '218', '148', '27'}): 6, frozenset({'148', '7', '27', '6'}): 5, frozenset({'218', '11', '1'}): 6, frozenset({'218', '27', '6'}): 7, frozenset({'6', '7', '218', '27', '11'}): 22, frozenset({'7', '11', '1', '3'}): 5, frozenset({'148', '11', '3'}): 9, frozenset({'3', '6', '7', '1', '218', '11'}): 12, frozenset({'218', '7', '1', '6'}): 10, frozenset({'3', '7', '1', '218', '27'}): 1, frozenset({'218', '11', '1', '3'}): 6, frozenset({'7', '11', '1'}): 3, frozenset({'218', '7', '27'}): 2, frozenset({'6', '1', '148', '27', '11'}): 3, frozenset({'218', '27', '1', '6'}): 5, frozenset({'3', '6', '1', '218', '148', '27'}): 6, frozenset({'148', '7'}): 3, frozenset({'148', '7', '1', '6'}): 3, frozenset({'3', '6', '11', '7', '1', '148', '27'}): 6, frozenset({'3', '6', '7', '1', '148', '11'}): 10, frozenset({'6', '3', '7', '148', '11'}): 8, frozenset({'148', '218', '11'}): 5, frozenset({'148', '1'}): 10, frozenset({'3', '6', '7', '1', '218'}): 7, frozenset({'11', '7', '27'}): 8, frozenset({'148', '218', '7'}): 2, frozenset({'218', '7', '11', '1'}): 1, frozenset({'3', '6', '7', '1', '218', '27'}): 4, frozenset({'3', '6', '7', '1', '218', '148', '27'}): 7, frozenset({'148', '11', '1'}): 3, frozenset({'11', '218', '27', '6'}): 7, frozenset({'218', '7', '3'}): 4, frozenset({'3', '6', '1', '148', '27', '11'}): 2, frozenset({'148', '218', '27'}): 2, frozenset({'6', '7', '1', '148', '27'}): 2, frozenset({'148', '27', '6'}): 1, frozenset({'148', '7', '6', '3'}): 3, frozenset({'3', '7', '1', '27', '11'}): 1, frozenset({'11', '218', '27'}): 1, frozenset({'148', '11', '1', '3'}): 2, frozenset({'3', '7', '1', '218', '148'}): 1, frozenset({'11', '7', '27', '3'}): 6, frozenset({'218', '7', '11', '3'}): 1, frozenset({'3', '7', '1', '218', '148', '27'}): 1, frozenset({'148', '218', '27', '1'}): 1, frozenset({'148', '27', '3'}): 1, frozenset({'218', '7', '27', '3'}): 2, frozenset({'218', '27'}): 4, frozenset({'6', '3', '7', '1', '148'}): 2, frozenset({'148', '27', '1', '6'}): 1, frozenset({'218', '27', '1', '3'}): 1, frozenset({'6', '3', '1', '218', '27'}): 2, frozenset({'3', '1', '218', '148', '27'}): 2, frozenset({'148', '218', '11', '3'}): 2, frozenset({'148', '218', '7', '1'}): 1, frozenset({'148', '218', '11', '1'}): 1, frozenset({'11', '218', '27', '3'}): 1, frozenset({'11', '7', '27', '1'}): 3, frozenset({'148', '27', '1', '3'}): 1, frozenset({'218', '7', '1'}): 1, frozenset({'148', '7', '3'}): 1, frozenset({'6', '7', '1', '218', '27'}): 2, frozenset({'3', '11', '7', '218', '148', '27'}): 1, frozenset({'148', '218', '27', '3'}): 1}\n",
      "head from conditional tree:  None\n",
      "finalFrequent Item:  {'27'}\n",
      "condPattBases : 27 {frozenset({'7', '11', '6', '3'}): 7036, frozenset({'6', '3', '7', '1', '11'}): 2667, frozenset({'11', '1', '6'}): 1501, frozenset({'7', '6', '3'}): 2026, frozenset({'7', '11', '6'}): 8773, frozenset({'6', '1', '3'}): 418, frozenset({'6', '7', '1', '218', '148', '11'}): 2153, frozenset({'11', '6'}): 3851, frozenset({'11'}): 263, frozenset({'3', '6', '7', '1', '218', '148', '11'}): 1641, frozenset({'6', '7', '218', '148', '11'}): 1839, frozenset({'7', '6'}): 2594, frozenset({'6', '7', '1', '3'}): 541, frozenset({'6', '3'}): 1927, frozenset({'3'}): 1979, frozenset({'11', '3'}): 230, frozenset({'6', '3', '7', '148', '11'}): 160, frozenset({'7', '11', '1', '6'}): 3226, frozenset({'6', '1', '218', '148', '11'}): 830, frozenset({'7'}): 1105, frozenset({'6', '11', '3'}): 3246, frozenset({'6'}): 2245, frozenset({'7', '3'}): 879, frozenset({'1', '3'}): 393, frozenset({'6', '7', '1', '218', '11'}): 223, frozenset({'3', '6', '7', '218', '148', '11'}): 1384, frozenset({'6', '3', '7', '218', '11'}): 360, frozenset({'148', '218'}): 24, frozenset({'6', '3', '218', '148', '11'}): 635, frozenset({'148', '218', '11', '6'}): 767, frozenset({'218', '11', '6'}): 160, frozenset({'1'}): 514, frozenset({'1', '6'}): 537, frozenset({'11', '1'}): 52, frozenset({'3', '6', '7', '1', '148', '11'}): 120, frozenset({'6', '11', '1', '3'}): 1190, frozenset({'218', '7', '1', '3'}): 6, frozenset({'7', '1', '6'}): 634, frozenset({'148', '218', '6'}): 77, frozenset({'218', '7', '11', '6'}): 385, frozenset({'3', '6', '1', '218', '148', '11'}): 655, frozenset({'218', '7', '6'}): 128, frozenset({'218', '6'}): 123, frozenset({'148', '7', '6', '3'}): 31, frozenset({'3', '6', '7', '1', '218', '11'}): 173, frozenset({'148', '7', '3'}): 8, frozenset({'6', '3', '1', '148', '11'}): 38, frozenset({'148', '11', '6'}): 86, frozenset({'11', '1', '3'}): 47, frozenset({'148', '218', '7', '1'}): 10, frozenset({'6', '7', '1', '218', '148'}): 123, frozenset({'148', '6', '11', '3'}): 74, frozenset({'7', '11', '3'}): 93, frozenset({'148', '218', '7', '6'}): 195, frozenset({'218'}): 67, frozenset({'6', '7', '1', '148', '11'}): 139, frozenset({'148', '11', '1', '6'}): 53, frozenset({'3', '7', '1', '218', '148'}): 11, frozenset({'218', '6', '3'}): 97, frozenset({'3', '6', '7', '1', '218', '148'}): 98, frozenset({'6', '3', '1', '218', '148'}): 48, frozenset({'7', '1'}): 210, frozenset({'218', '7', '1', '6'}): 69, frozenset({'218', '11'}): 12, frozenset({'148', '3'}): 27, frozenset({'148', '6'}): 32, frozenset({'218', '6', '1', '3'}): 35, frozenset({'6', '3', '7', '1', '148'}): 11, frozenset({'218', '7', '3'}): 27, frozenset({'148', '218', '1', '3'}): 11, frozenset({'148', '218', '1', '6'}): 42, frozenset({'218', '6', '11', '3'}): 159, frozenset({'6', '3', '7', '218', '148'}): 117, frozenset({'218', '7', '6', '3'}): 102, frozenset({'7', '11'}): 128, frozenset({'218', '11', '1', '6'}): 94, frozenset({'148', '218', '6', '3'}): 71, frozenset({'218', '3'}): 44, frozenset({'7', '1', '3'}): 167, frozenset({'6', '3', '1', '218', '11'}): 85, frozenset({'148', '7', '6'}): 39, frozenset({'148', '7', '11', '6'}): 195, frozenset({'148', '1', '6'}): 11, frozenset({'148', '218', '7'}): 20, frozenset({'148', '6', '3'}): 23, frozenset({'3', '6', '7', '1', '218'}): 57, frozenset({'218', '7'}): 31, frozenset({'7', '11', '1'}): 22, frozenset({'218', '1', '6'}): 54, frozenset({'218', '11', '3'}): 10, frozenset({'148'}): 21, frozenset({'148', '7'}): 9, frozenset({'148', '1'}): 6, frozenset({'3', '7', '218', '148', '11'}): 4, frozenset({'148', '7', '1', '6'}): 13, frozenset({'218', '1'}): 9, frozenset({'7', '11', '1', '3'}): 11, frozenset({'148', '218', '7', '3'}): 11, frozenset({'148', '218', '3'}): 21, frozenset({'148', '7', '1'}): 4, frozenset({'218', '11', '1', '3'}): 2, frozenset({'218', '7', '11', '3'}): 3, frozenset({'148', '6', '1', '3'}): 6, frozenset({'148', '218', '1'}): 11, frozenset({'218', '7', '1'}): 5, frozenset({'148', '7', '11', '1'}): 1, frozenset({'148', '218', '11'}): 2, frozenset({'148', '218', '7', '11'}): 3, frozenset({'148', '7', '11'}): 2, frozenset({'148', '7', '1', '3'}): 3, frozenset({'148', '11'}): 3, frozenset({'3', '7', '1', '218', '148', '11'}): 1, frozenset({'218', '1', '3'}): 8, frozenset({'148', '11', '3'}): 2, frozenset({'148', '218', '11', '1'}): 2, frozenset({'148', '1', '3'}): 3, frozenset({'148', '11', '1'}): 1, frozenset({'3', '7', '1', '218', '11'}): 1, frozenset({'148', '218', '11', '3'}): 2, frozenset({'218', '7', '11', '1'}): 1, frozenset({'218', '11', '1'}): 1}\n",
      "head from conditional tree:  {'6': [56422, <fpGrowth.treeNode object at 0x000001E89414DE88>]}\n",
      "conditional tree for:  {'27'}\n",
      "  Null Set   1\n",
      "   6   56422\n",
      "finalFrequent Item:  {'27', '6'}\n",
      "condPattBases : 6 {}\n",
      "head from conditional tree:  None\n",
      "finalFrequent Item:  {'148'}\n",
      "condPattBases : 148 {frozenset({'3'}): 688, frozenset({'6', '3', '1', '218', '11'}): 6872, frozenset({'218', '11', '6'}): 11950, frozenset({'3', '6', '7', '1', '218', '11'}): 2742, frozenset({'218', '6', '11', '3'}): 9102, frozenset({'6', '7', '1', '218', '11'}): 3541, frozenset({'11', '1', '6'}): 702, frozenset({'218', '7', '11', '6'}): 3236, frozenset({'6', '3'}): 591, frozenset({'1', '3'}): 137, frozenset({'6', '11', '3'}): 1197, frozenset({'7', '11', '6', '3'}): 310, frozenset({'218', '11', '1', '6'}): 9193, frozenset({'218', '6'}): 2120, frozenset({'7', '11', '6'}): 389, frozenset({'6', '11', '1', '3'}): 607, frozenset({'6', '3', '7', '218', '11'}): 2519, frozenset({'218', '6', '3'}): 1624, frozenset({'218'}): 615, frozenset({'218', '6', '1', '3'}): 752, frozenset({'218', '11'}): 89, frozenset({'218', '7', '1', '3'}): 23, frozenset({'6'}): 759, frozenset({'7', '11', '1', '6'}): 243, frozenset({'6', '3', '7', '1', '11'}): 213, frozenset({'1'}): 149, frozenset({'11', '6'}): 1420, frozenset({'1', '6'}): 202, frozenset({'218', '1', '6'}): 1014, frozenset({'7', '6', '3'}): 73, frozenset({'7'}): 41, frozenset({'218', '3'}): 435, frozenset({'6', '1', '3'}): 174, frozenset({'7', '3'}): 22, frozenset({'218', '7', '1'}): 27, frozenset({'3', '6', '7', '1', '218'}): 213, frozenset({'218', '7', '1', '6'}): 248, frozenset({'218', '7', '6'}): 392, frozenset({'7', '6'}): 84, frozenset({'11'}): 90, frozenset({'218', '1'}): 244, frozenset({'7', '11', '3'}): 3, frozenset({'218', '1', '3'}): 184, frozenset({'218', '11', '3'}): 61, frozenset({'6', '7', '1', '3'}): 23, frozenset({'218', '7', '6', '3'}): 292, frozenset({'11', '3'}): 84, frozenset({'7', '11', '1'}): 3, frozenset({'218', '11', '1'}): 29, frozenset({'218', '7', '3'}): 40, frozenset({'7', '11', '1', '3'}): 1, frozenset({'218', '7'}): 58, frozenset({'7', '1', '6'}): 36, frozenset({'218', '11', '1', '3'}): 26, frozenset({'7', '11'}): 6, frozenset({'218', '7', '11', '3'}): 7, frozenset({'218', '7', '11'}): 4, frozenset({'11', '1'}): 17, frozenset({'11', '1', '3'}): 17, frozenset({'7', '1'}): 6, frozenset({'3', '7', '1', '218', '11'}): 3, frozenset({'7', '1', '3'}): 5}\n",
      "head from conditional tree:  {'6': [62833, <fpGrowth.treeNode object at 0x000001E894163208>], '218': [57655, <fpGrowth.treeNode object at 0x000001E894163248>], '11': [54676, <fpGrowth.treeNode object at 0x000001E894163288>]}\n",
      "conditional tree for:  {'148'}\n",
      "  Null Set   1\n",
      "   6   62833\n",
      "    218   55810\n",
      "     11   49155\n",
      "    11   5081\n",
      "   218   1845\n",
      "    11   219\n",
      "   11   221\n",
      "finalFrequent Item:  {'148', '11'}\n",
      "condPattBases : 11 {frozenset({'218', '6'}): 49155, frozenset({'6'}): 5081, frozenset({'218'}): 219}\n",
      "head from conditional tree:  {'6': [54236, <fpGrowth.treeNode object at 0x000001E8941638C8>]}\n",
      "conditional tree for:  {'148', '11'}\n",
      "  Null Set   1\n",
      "   6   54236\n",
      "finalFrequent Item:  {'148', '11', '6'}\n",
      "condPattBases : 6 {}\n",
      "head from conditional tree:  None\n",
      "finalFrequent Item:  {'148', '218'}\n",
      "condPattBases : 218 {frozenset({'6'}): 55810}\n",
      "head from conditional tree:  {'6': [55810, <fpGrowth.treeNode object at 0x000001E894163B48>]}\n",
      "conditional tree for:  {'148', '218'}\n",
      "  Null Set   1\n",
      "   6   55810\n",
      "finalFrequent Item:  {'148', '218', '6'}\n",
      "condPattBases : 6 {}\n",
      "head from conditional tree:  None\n",
      "finalFrequent Item:  {'148', '6'}\n",
      "condPattBases : 6 {}\n",
      "head from conditional tree:  None\n",
      "finalFrequent Item:  {'7'}\n",
      "condPattBases : 7 {frozenset({'6'}): 5889, frozenset({'1', '3'}): 587, frozenset({'6', '11', '3'}): 13116, frozenset({'6', '11', '1', '3'}): 4846, frozenset({'6', '3'}): 4804, frozenset({'6', '3', '1', '218', '11'}): 3076, frozenset({'11', '6'}): 15993, frozenset({'218', '11', '1', '6'}): 3970, frozenset({'3'}): 3047, frozenset({'11'}): 422, frozenset({'218', '11', '6'}): 3987, frozenset({'6', '1', '3'}): 1162, frozenset({'11', '1', '6'}): 5931, frozenset({'218', '6', '11', '3'}): 3188, frozenset({'218', '1', '3'}): 40, frozenset({'218', '1', '6'}): 419, frozenset({'1', '6'}): 1475, frozenset({'218', '6'}): 732, frozenset({'1'}): 757, frozenset({'11', '3'}): 348, frozenset({'218', '1'}): 52, frozenset({'218', '6', '1', '3'}): 349, frozenset({'218', '3'}): 140, frozenset({'218', '6', '3'}): 576, frozenset({'218'}): 160, frozenset({'11', '1'}): 81, frozenset({'11', '1', '3'}): 71, frozenset({'218', '11'}): 14, frozenset({'218', '11', '3'}): 16, frozenset({'218', '11', '1'}): 3, frozenset({'218', '11', '1', '3'}): 5}\n",
      "head from conditional tree:  {'6': [69513, <fpGrowth.treeNode object at 0x000001E894163E88>], '11': [55067, <fpGrowth.treeNode object at 0x000001E894163F48>]}\n",
      "conditional tree for:  {'7'}\n",
      "  Null Set   1\n",
      "   6   69513\n",
      "    11   54107\n",
      "   11   960\n",
      "finalFrequent Item:  {'7', '11'}\n",
      "condPattBases : 11 {frozenset({'6'}): 54107}\n",
      "head from conditional tree:  {'6': [54107, <fpGrowth.treeNode object at 0x000001E89414F2C8>]}\n",
      "conditional tree for:  {'7', '11'}\n",
      "  Null Set   1\n",
      "   6   54107\n",
      "finalFrequent Item:  {'7', '11', '6'}\n",
      "condPattBases : 6 {}\n",
      "head from conditional tree:  None\n",
      "finalFrequent Item:  {'7', '6'}\n",
      "condPattBases : 6 {}\n",
      "head from conditional tree:  None\n",
      "finalFrequent Item:  {'218'}\n",
      "condPattBases : 218 {frozenset({'6', '11', '1', '3'}): 10986, frozenset({'11', '6'}): 18750, frozenset({'6', '11', '3'}): 14769, frozenset({'11', '1', '6'}): 14390, frozenset({'6'}): 5679, frozenset({'11'}): 335, frozenset({'6', '3'}): 4575, frozenset({'1', '6'}): 2428, frozenset({'6', '1', '3'}): 1851, frozenset({'1'}): 715, frozenset({'1', '3'}): 587, frozenset({'3'}): 2262, frozenset({'11', '3'}): 285, frozenset({'11', '1'}): 81, frozenset({'11', '1', '3'}): 73}\n",
      "head from conditional tree:  {'6': [73428, <fpGrowth.treeNode object at 0x000001E89414F688>], '11': [59669, <fpGrowth.treeNode object at 0x000001E89414F6C8>]}\n",
      "conditional tree for:  {'218'}\n",
      "  Null Set   1\n",
      "   6   73428\n",
      "    11   58895\n",
      "   11   774\n",
      "finalFrequent Item:  {'218', '11'}\n",
      "condPattBases : 11 {frozenset({'6'}): 58895}\n",
      "head from conditional tree:  {'6': [58895, <fpGrowth.treeNode object at 0x000001E89414FA08>]}\n",
      "conditional tree for:  {'218', '11'}\n",
      "  Null Set   1\n",
      "   6   58895\n",
      "finalFrequent Item:  {'218', '11', '6'}\n",
      "condPattBases : 6 {}\n",
      "head from conditional tree:  None\n",
      "finalFrequent Item:  {'218', '6'}\n",
      "condPattBases : 6 {}\n",
      "head from conditional tree:  None\n",
      "浏览次数在5万次以上的新闻报导集合个数： 29\n",
      "浏览次数在5万次以上的新闻：\n",
      " [{'1'}, {'1', '6'}, {'1', '3'}, {'11', '1'}, {'11', '1', '6'}, {'3'}, {'11', '3'}, {'6', '11', '3'}, {'6', '3'}, {'11'}, {'11', '6'}, {'6'}, {'4'}, {'27'}, {'27', '6'}, {'148'}, {'148', '11'}, {'148', '11', '6'}, {'148', '218'}, {'148', '218', '6'}, {'148', '6'}, {'7'}, {'7', '11'}, {'7', '11', '6'}, {'7', '6'}, {'218'}, {'218', '11'}, {'218', '11', '6'}, {'218', '6'}]\n"
     ]
    }
   ],
   "source": [
    "import fpGrowth\n",
    "\n",
    "# 读取数据并转换格式\n",
    "newsdata = [line.split() for line in open('../data/kosarak.dat').readlines()]\n",
    "indataset = fpGrowth.createInitSet(newsdata)\n",
    "# 构建树寻找其中浏览次数在5万次以上的新闻\n",
    "news_fptree, news_headertab = fpGrowth.createTree(indataset, 50000)\n",
    "# 创建空列表用于保持频繁项集\n",
    "newslist = []\n",
    "fpGrowth.mineTree(news_fptree, news_headertab, 50000, set([]), newslist)\n",
    "# 查看结果\n",
    "print('浏览次数在5万次以上的新闻报导集合个数：', len(newslist))\n",
    "print('浏览次数在5万次以上的新闻：\\n', newslist)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 基于协同过滤的智能推荐"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "用户预测评分的前5行：\n",
      " movid       mov1      mov2      mov3      mov4      mov5      mov6      mov7  \\\n",
      "userid                                                                         \n",
      "usr1    5.000000  3.000000  4.000000  3.000000  3.000000       NaN  4.000000   \n",
      "usr2    4.000000  3.380623  3.290610  3.738864  3.957481  3.658084  4.201094   \n",
      "usr3    3.321139  2.856091       NaN  2.719730  2.829381       NaN  3.193685   \n",
      "usr4         NaN       NaN       NaN       NaN       NaN       NaN       NaN   \n",
      "usr5    3.520812  2.915504  2.555488  3.406287  2.576585       NaN  3.594763   \n",
      "\n",
      "movid       mov8      mov9     mov10  ...  mov1673  mov1674  mov1675  mov1676  \\\n",
      "userid                                ...                                       \n",
      "usr1    1.000000  5.000000  3.779174  ...      NaN      NaN      NaN      NaN   \n",
      "usr2    3.801101  4.162900  2.000000  ...      NaN      NaN      NaN      NaN   \n",
      "usr3    4.160415  3.189360       NaN  ...      NaN      NaN      NaN      NaN   \n",
      "usr4         NaN       NaN       NaN  ...      NaN      NaN      NaN      NaN   \n",
      "usr5    4.103063  4.408153  3.535268  ...      NaN      NaN      NaN      NaN   \n",
      "\n",
      "movid   mov1677  mov1678  mov1679  mov1680  mov1681  mov1682  \n",
      "userid                                                        \n",
      "usr1        NaN      NaN      NaN      NaN      NaN      NaN  \n",
      "usr2        NaN      NaN      NaN      NaN      NaN      NaN  \n",
      "usr3        NaN      NaN      NaN      NaN      NaN      NaN  \n",
      "usr4        NaN      NaN      NaN      NaN      NaN      NaN  \n",
      "usr5        NaN      NaN      NaN      NaN      NaN      NaN  \n",
      "\n",
      "[5 rows x 1650 columns]\n",
      "用户推荐列表的前5行：\n",
      " [Index(['mov479', 'mov302', 'mov100'], dtype='object', name='movid'), Index(['mov603', 'mov169', 'mov318'], dtype='object', name='movid'), Index(['mov408', 'mov432', 'mov507'], dtype='object', name='movid'), Index(['mov100', 'mov302', 'mov923'], dtype='object', name='movid'), Index(['mov127', 'mov180', 'mov56'], dtype='object', name='movid')]\n"
     ]
    }
   ],
   "source": [
    "# 使用基于UBCF算法对电影进行推荐\n",
    "import pandas as pd\n",
    "from recommender import recomm  # 加载自编推荐函数\n",
    "\n",
    "# 读入数据\n",
    "traindata = pd.read_csv('../data/u1.base', sep='\\t', header=None, index_col=None)\n",
    "testdata = pd.read_csv('../data/u1.test', sep='\\t', header=None, index_col=None)\n",
    "# 删除时间标签列\n",
    "traindata.drop(3, axis=1, inplace=True)\n",
    "testdata.drop(3, axis=1, inplace=True)\n",
    "# 行与列重新命名\n",
    "traindata.rename(columns={0: 'userid', 1: 'movid', 2: 'rat'}, inplace=True)\n",
    "testdata.rename(columns={0: 'userid', 1: 'movid', 2: 'rat'}, inplace=True)\n",
    "traindf = traindata.pivot(index='userid', columns='movid', values='rat')\n",
    "testdf = testdata.pivot(index='userid', columns='movid', values='rat')\n",
    "traindf.rename(index={i: 'usr%d' % (i) for i in traindf.index}, inplace=True)\n",
    "traindf.rename(columns={i: 'mov%d' % (i) for i in traindf.columns}, inplace=True)\n",
    "testdf.rename(index={i: 'usr%d' % (i) for i in testdf.index}, inplace=True)\n",
    "testdf.rename(columns={i: 'mov%d' % (i) for i in testdf.columns}, inplace=True)\n",
    "userdf = traindf.loc[testdf.index]\n",
    "# 获取预测评分和推荐列表\n",
    "trainrats, trainrecomm = recomm(traindf, userdf)\n",
    "print('用户预测评分的前5行：\\n', trainrats.head())\n",
    "\n",
    "# 保存预测的评分\n",
    "trainrats.to_csv('../tmp/movie_comm.csv', index=False, encoding='utf-8')\n",
    "print('用户推荐列表的前5行：\\n', trainrecomm[:5])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "训练集电影数： 1650\n",
      "训练集用户观影次数： 80000\n",
      "推荐结果前5行: \n",
      "    User  已观看电影 推荐电影    T/F\n",
      "0     1      6  546  False\n",
      "1     1     10   19  False\n",
      "2     1     12   10   True\n",
      "3     1     14  274  False\n",
      "4     1     17   67   True\n"
     ]
    }
   ],
   "source": [
    "import pandas as pd\n",
    "\n",
    "# 读入数据\n",
    "traindata = pd.read_csv('../data/u1.base', sep='\\t', header=None, index_col=None)\n",
    "testdata = pd.read_csv('../data/u1.test', sep='\\t', header=None, index_col=None)\n",
    "# 删除时间标签列\n",
    "traindata.drop(3, axis=1, inplace=True)\n",
    "testdata.drop(3, axis=1, inplace=True)\n",
    "# 行与列重新命名\n",
    "traindata.rename(columns={0: 'userid', 1: 'movid', 2: 'rat'}, inplace=True)\n",
    "testdata.rename(columns={0: 'userid', 1: 'movid', 2: 'rat'}, inplace=True)\n",
    "# 构建训练集数据\n",
    "user_tr = traindata.iloc[:, 0]  # 训练集用户id\n",
    "mov_tr = traindata.iloc[:, 1]  # 训练集电影id\n",
    "user_tr = list(set(user_tr))  # 去重处理\n",
    "mov_tr = list(set(mov_tr))  # 去重处理\n",
    "print('训练集电影数：', len(mov_tr))\n",
    "\n",
    "# 利用训练集数据构建模型\n",
    "ui_matrix_tr = pd.DataFrame(0, index=user_tr, columns=mov_tr)\n",
    "# 求用户－物品矩阵\n",
    "for i in traindata.index:\n",
    "    ui_matrix_tr.loc[traindata.loc[i, 'userid'], traindata.loc[i, 'movid']] = 1\n",
    "print('训练集用户观影次数：', sum(ui_matrix_tr.sum(axis=1)))\n",
    "\n",
    "# 求物品相似度矩阵（因计算量较大，需要耗费的时间较久）\n",
    "item_matrix_tr = pd.DataFrame(0, index=mov_tr, columns=mov_tr)\n",
    "for i in item_matrix_tr.index:\n",
    "    for j in item_matrix_tr.index:\n",
    "        a = sum(ui_matrix_tr.loc[:, [i, j]].sum(axis=1) == 2)\n",
    "        b = sum(ui_matrix_tr.loc[:, [i, j]].sum(axis=1) != 0)\n",
    "        item_matrix_tr.loc[i, j] = a / b\n",
    "# 将物品相似度矩阵对角线处理为零\n",
    "for i in item_matrix_tr.index:\n",
    "    item_matrix_tr.loc[i, i] = 0\n",
    "# 利用测试集数据对模型评价\n",
    "user_te = testdata.iloc[:, 0]\n",
    "mov_te = testdata.iloc[:, 1]\n",
    "user_te = list(set(user_te))\n",
    "mov_te = list(set(mov_te))\n",
    "# 测试集数据用户物品矩阵\n",
    "ui_matrix_te = pd.DataFrame(0, index=user_te, columns=mov_te)\n",
    "for i in testdata.index:\n",
    "    ui_matrix_te.loc[testdata.loc[i, 'userid'], testdata.loc[i, 'movid']] = 1\n",
    "# 对测试集用户进行推荐\n",
    "res = pd.DataFrame('NaN', index=testdata.index, columns=['User', '已观看电影', '推荐电影', 'T/F'])\n",
    "res.loc[:, 'User'] = list(testdata.iloc[:, 0])\n",
    "res.loc[:, '已观看电影'] = list(testdata.iloc[:, 1])\n",
    "# 开始推荐\n",
    "for i in res.index:\n",
    "    if res.loc[i, '已观看电影'] in list(item_matrix_tr.index):\n",
    "        res.loc[i, '推荐电影'] = item_matrix_tr.loc[res.loc[i, '已观看电影'], :].argmax()\n",
    "        if res.loc[i, '推荐电影'] in mov_te:\n",
    "            res.loc[i, 'T/F'] = ui_matrix_te.loc[res.loc[i, 'User'], res.loc[i, '推荐电影']] == 1\n",
    "        else:\n",
    "            res.loc[i, 'T/F'] = False\n",
    "# 保存推荐结果\n",
    "res.to_csv('../tmp/res_mov.csv', index=False, encoding='utf8')\n",
    "print('推荐结果前5行: \\n', res.head())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
